home *** CD-ROM | disk | FTP | other *** search
/ IRIX 6.3 Development Libraries / SGI IRIX 6.3 Development Libraries.iso / dist6.3 / gl_dev.idb / usr / share / src / OpenGL / teach / motif / mtablet.c.z / mtablet.c
Encoding:
C/C++ Source or Header  |  1996-12-06  |  11.7 KB  |  418 lines

  1.  
  2. /* mtablet.c - OpenGL Motif program using tablet events */
  3.  
  4. /* Note that this program relies on Xt interfaces for handling X
  5.    extension events introduced with X11R6. */
  6.  
  7. /* compile: cc -o mouse mouse.c -lGLw -lGLU -lGL -lXm -lXt -Xi
  8.    -lXext -lX11 */
  9.  
  10. #include <assert.h>
  11. #include <stdlib.h>
  12. #include <stdio.h>
  13. #include <Xm/Frame.h>
  14. #include <Xm/RowColumn.h>
  15. #include <X11/GLw/GLwMDrawA.h>
  16. #include <X11/keysym.h>
  17. #include <X11/Xutil.h>
  18. #include <X11/extensions/XInput.h>
  19. #include <X11/extensions/XIproto.h>  /* For IEVENTS,
  20.                                         unfortunately not in
  21.                                         XInput.h */
  22.  
  23. int attribs[] = { GLX_RGBA, GLX_RED_SIZE, 1, GLX_DOUBLEBUFFER, None};
  24. String fallbackResources[] = {
  25.   "*glxwidget*width: 300",
  26.   "*glxwidget*height: 300",
  27.   "*sgiMode: True",
  28.   NULL
  29. };
  30.  
  31. Display *dpy;
  32. XtAppContext appctx;
  33. Widget glxwidget;
  34. XDevice *tablet;
  35. int tablet_motion_notify, tablet_press_notify,
  36.   tablet_release_notify;
  37. int win_width, win_height;
  38. int axis_min[2];
  39. int axis_range[2];
  40. GLenum btn_state[4] = {GL_LINE, GL_LINE, GL_LINE, GL_LINE};
  41. int tablet_pos[2] = {2000, 2000};
  42. Bool direct, redisplay_posted = False;
  43.  
  44. void expose(Widget w, XtPointer client_data, XtPointer call);
  45. void resize(Widget w, XtPointer client_data, XtPointer call);
  46. void initialize_tablet(void);
  47.  
  48. void
  49. main(int argc, char *argv[])
  50. {
  51.   XVisualInfo *visinfo;
  52.   GLXContext glxcontext;
  53.   Widget toplevel, frame;
  54.  
  55.   toplevel = XtOpenApplication(&appctx, "tablet", NULL, 0, &argc, argv,
  56.     fallbackResources, applicationShellWidgetClass, NULL, 0);
  57.   dpy = XtDisplay(toplevel);
  58.  
  59.   frame = XmCreateFrame(toplevel, "frame", NULL, 0);
  60.   XtManageChild(frame);
  61.  
  62.   /* specify visual directly */
  63.   if (!(visinfo = glXChooseVisual(dpy, DefaultScreen(dpy), attribs)))
  64.     XtAppError(appctx, "no suitable RGB visual");
  65.  
  66.   glxwidget = XtVaCreateManagedWidget("glxwidget", glwMDrawingAreaWidgetClass,
  67.     frame, GLwNvisualInfo, visinfo, XtNwidth, 300, XtNheight, 300, NULL);
  68.   XtAddCallback(glxwidget, GLwNexposeCallback, expose, NULL);
  69.   XtAddCallback(glxwidget, GLwNresizeCallback, resize, NULL);
  70.  
  71.   initialize_tablet();
  72.  
  73.   XtRealizeWidget(toplevel);
  74.  
  75.   glxcontext = glXCreateContext(dpy, visinfo, 0, GL_TRUE);
  76.   direct = glXIsDirect(dpy, glxcontext);
  77.   GLwDrawingAreaMakeCurrent(glxwidget, glxcontext);
  78.  
  79.   glMatrixMode(GL_PROJECTION);
  80.   glOrtho(0, 4000, 0, 4000, 0, 1);
  81.   glMatrixMode(GL_MODELVIEW);
  82.   glClearColor(0.5, 0.5, 0.5, 0.);
  83.  
  84.   XtAppMainLoop(appctx);
  85. }
  86.  
  87. void select_xinput_events(Widget w, int *event_types,
  88.   XtPointer * select_data, int count, XtPointer client_data);
  89. Boolean dispatch_xinput_event(XEvent * event);
  90. void tablet_handler(Widget w, XtPointer client_data,
  91.   XEvent * event, Boolean * continue_to_dispatch);
  92.  
  93. void
  94. initialize_tablet(void)
  95. {
  96.   Bool exists;
  97.   XExtensionVersion *version;
  98.   XDeviceInfoPtr device_info, device;
  99.   XAnyClassPtr any;
  100.   XEventClass tablet_motion_class, tablet_press_class, tablet_press_grab_class,
  101.     tablet_release_class;
  102.   XButtonInfoPtr b;
  103.   XValuatorInfoPtr v;
  104.   XAxisInfoPtr a;
  105.   int opcode, event_base, error_base;
  106.   int num_dev;
  107.   int i, j, k;
  108.  
  109.   exists = XQueryExtension(dpy, "XInputExtension", &opcode,
  110.     &event_base, &error_base);
  111.   if (!exists) {
  112.     return;
  113.   }
  114.   version = XGetExtensionVersion(dpy, "XInputExtension");
  115.   if (version == NULL || ((int) version) == NoSuchExtension) {
  116.     return;
  117.   }
  118.   XFree(version);
  119.   device_info = XListInputDevices(dpy, &num_dev);
  120.   if (device_info) {
  121.     for (i = 0; i < num_dev; i++) {
  122.       device = &device_info[i];
  123.       any = (XAnyClassPtr) device->inputclassinfo;
  124.  
  125.       if (!strcmp(device->name, "tablet")) {
  126.         v = NULL;
  127.         b = NULL;
  128.         for (j = 0; j < device->num_classes; j++) {
  129.           switch (any->class) {
  130.           case ButtonClass:
  131.             b = (XButtonInfoPtr) any;
  132.             /* Sanity check: at least 1 button (normally 4). */
  133.             if (b->num_buttons < 1) {
  134.               goto skip_device;
  135.             }
  136.             break;
  137.           case ValuatorClass:
  138.             v = (XValuatorInfoPtr) any;
  139.             /* Sanity check: exactly 2 valuators? */
  140.             if (v->num_axes != 2) {
  141.               goto skip_device;
  142.             }
  143.             a = (XAxisInfoPtr) ((char *) v + sizeof(XValuatorInfo));
  144.             for (k = 0; k < 2; k++, a++) {
  145.               axis_min[k] = a->min_value;
  146.               axis_range[k] = a->max_value - a->min_value;
  147.             }
  148.             break;
  149.           }
  150.           any = (XAnyClassPtr) ((char *) any + any->length);
  151.         }
  152.         tablet = XOpenDevice(dpy, device->id);
  153.         if (tablet) {
  154.  
  155.           /* From the tablet device, extract the type and class 
  156.              of the motion notify, button press, and button
  157.              release events. */
  158.           DeviceMotionNotify(tablet,
  159.             tablet_motion_notify, tablet_motion_class);
  160.           DeviceButtonPress(tablet,
  161.             tablet_press_notify, tablet_press_class);
  162.           DeviceButtonPressGrab(tablet,
  163.             not_used_by_macro, tablet_press_grab_class);
  164.           DeviceButtonRelease(tablet,
  165.             tablet_release_notify, tablet_release_class);
  166.  
  167.           /* Register an event selection routine for the X
  168.              Input extension events so Xt will know how to
  169.              select for these events for a specific widget when 
  170.              XtInsertEventTypeHandler is used to supply an
  171.              event handler for an X Input extension event for a 
  172.              widget. */
  173.           XtRegisterExtensionSelector(dpy, event_base,
  174.             event_base + IEVENTS - 1, select_xinput_events, NULL);
  175.  
  176.           /* Register a dispatch procedure for the various X
  177.              Input extension events  so Xt will know to
  178.              dispatch these events instead of discarding them. */
  179.           XtSetEventDispatcher(dpy, tablet_motion_notify,
  180.         dispatch_xinput_event);
  181.           XtSetEventDispatcher(dpy, tablet_press_notify,
  182.         dispatch_xinput_event);
  183.           XtSetEventDispatcher(dpy, tablet_release_notify,
  184.         dispatch_xinput_event);
  185.  
  186.           /* Provide an event handler for the given widget for
  187.              the given X Input extension event. */
  188.           XtInsertEventTypeHandler(glxwidget,
  189.             tablet_motion_notify, (XtPointer) tablet_motion_class,
  190.             tablet_handler, NULL, XtListTail);
  191.           XtInsertEventTypeHandler(glxwidget,
  192.             tablet_press_notify, (XtPointer) tablet_press_class,
  193.             tablet_handler, NULL, XtListTail);
  194.           XtInsertEventTypeHandler(glxwidget,
  195.             tablet_press_notify, (XtPointer) tablet_press_grab_class,
  196.             tablet_handler, NULL, XtListTail);
  197.           XtInsertEventTypeHandler(glxwidget,
  198.             tablet_release_notify, (XtPointer) tablet_release_class,
  199.             tablet_handler, NULL, XtListTail);
  200.  
  201.           /* Tablet found and setup, look no further. */
  202.           XFreeDeviceList(device_info);
  203.           return;
  204.         }
  205.       }
  206.     skip_device:;
  207.     }
  208.     XFreeDeviceList(device_info);
  209.   }
  210.   /* Did not find tablet device. */
  211.   fprintf(stderr, "wtablet: no tablet device found!\n");
  212.   fprintf(stderr, "         continuing without tablet support.\n");
  213.   return;
  214. }
  215.  
  216. void
  217. select_xinput_events(Widget w, int *event_types,
  218.   XtPointer * select_data, int count, XtPointer client_data)
  219. {
  220.   XEventClass *xcp = (XEventClass *) select_data;
  221.  
  222.   XSelectExtensionEvent(XtDisplay(w), XtWindow(w), xcp, count);
  223. }
  224.  
  225. Boolean
  226. dispatch_xinput_event(XEvent * event)
  227. {
  228.   Widget w;
  229.   XAnyEvent *xany = (XAnyEvent *) event;
  230.  
  231.   w = XtWindowToWidget(xany->display, xany->window);
  232.  
  233.   /* Potentially, you could insert "w =
  234.      XtGetKeyboardFocusWidget(w);" if you wished to redirect
  235.      the X Input extension events to the widget with keyboard
  236.      focus.  This is almost certainly, not what you would want
  237.      for a device like a tablet that has a sense of position
  238.      within the window for which the events are generated, but
  239.      for another device like an alternate keyboard,
  240.      XtGetKeyboardFocusWidget might be appropriate. */
  241.  
  242.   if (!XFilterEvent(event, (w == NULL) ? None : XtWindow(w))) {
  243.     return XtDispatchEventToWidget(w, event);
  244.   } else {
  245.     return True;
  246.   }
  247. }
  248.  
  249. void tablet_pos_change(int first, int count, int *data);
  250. void post_redisplay(void);
  251.  
  252. void
  253. tablet_handler(Widget w, XtPointer client_data,
  254.   XEvent * event, Boolean * continue_to_dispatch)
  255. {
  256.   if (event->type == tablet_motion_notify) {
  257.     XDeviceMotionEvent *devmot = (XDeviceMotionEvent *) event;
  258.  
  259.     tablet_pos_change(devmot->first_axis, devmot->axes_count,
  260.       devmot->axis_data);
  261.   } else if (event->type == tablet_press_notify) {
  262.     XDeviceButtonPressedEvent *devbtn = (XDeviceButtonEvent *) event;
  263.  
  264.     btn_state[devbtn->button - 1] = GL_FILL;
  265.     post_redisplay();
  266.   } else if (event->type == tablet_release_notify) {
  267.     XDeviceButtonReleasedEvent *devbtn = (XDeviceButtonEvent *) event;
  268.  
  269.     btn_state[devbtn->button - 1] = GL_LINE;
  270.     post_redisplay();
  271.   }
  272. }
  273.  
  274. int normalize_tablet_pos(int axis, int rawValue);
  275. void query_tablet_pos(void);
  276.  
  277. void
  278. tablet_pos_change(int first, int count, int *data)
  279. {
  280.   int i, value, genEvent = 0;
  281.  
  282.   for (i = first; i < first + count; i++) {
  283.     switch (i) {
  284.     case 0:            /* X axis */
  285.     case 1:            /* Y axis */
  286.       value = normalize_tablet_pos(i, data[i - first]);
  287.       if (value != tablet_pos[i]) {
  288.         tablet_pos[i] = value;
  289.         genEvent = 1;
  290.       }
  291.       break;
  292.     }
  293.   }
  294.   if (tablet_pos[0] == -1 || tablet_pos[1] == -1)
  295.     query_tablet_pos();
  296.   if (genEvent) {
  297.     post_redisplay();
  298.   }
  299. }
  300.  
  301. int
  302. normalize_tablet_pos(int axis, int rawValue)
  303. {
  304.   assert(rawValue >= axis_min[axis]);
  305.   assert(rawValue <= axis_min[axis] + axis_range[axis]);
  306.   /* Normalize rawValue to between 0 and 4000. */
  307.   return ((rawValue - axis_min[axis]) * 4000) /
  308.     axis_range[axis];
  309. }
  310.  
  311. void
  312. query_tablet_pos(void)
  313. {
  314.   XDeviceState *state;
  315.   XInputClass *any;
  316.   XValuatorState *v;
  317.   int i;
  318.  
  319.   state = XQueryDeviceState(dpy, tablet);
  320.   any = state->data;
  321.   for (i = 0; i < state->num_classes; i++) {
  322.     switch (any->class) {
  323.     case ValuatorClass:
  324.       v = (XValuatorState *) any;
  325.       if (v->num_valuators < 2)
  326.         goto end;
  327.       if (tablet_pos[0] == -1)
  328.         tablet_pos[0] = normalize_tablet_pos(0, v->valuators[0]);
  329.       if (tablet_pos[1] == -1)
  330.         tablet_pos[1] = normalize_tablet_pos(1, v->valuators[1]);
  331.     }
  332.     any = (XInputClass *) ((char *) any + any->length);
  333.   }
  334. end:
  335.   XFreeDeviceState(state);
  336. }
  337.  
  338. void draw_scene(void);
  339.  
  340. void
  341. do_redisplay(void *client_data, XtIntervalId * id)
  342. {
  343.   draw_scene();
  344.   redisplay_posted = False;
  345. }
  346.  
  347. void
  348. post_redisplay(void)
  349. {
  350.   if (!redisplay_posted) {
  351.     redisplay_posted = True;
  352.     XtAppAddTimeOut(appctx, 5, do_redisplay, NULL);
  353.   }
  354. }
  355.  
  356. void
  357. expose(Widget w, XtPointer client_data, XtPointer call)
  358. {
  359.   post_redisplay();
  360. }
  361.  
  362. void
  363. diamond(GLenum mode)
  364. {                  
  365.   glPushMatrix();
  366.   glPolygonMode(GL_FRONT_AND_BACK, mode);
  367.   glRotatef(45., 0., 0., 1.);
  368.   glRectf(-0.5, -0.5, 1, 1);
  369.   glPopMatrix();
  370. }
  371.  
  372. void
  373. puck(void)
  374. {                    
  375.   /* Make a puck out of 4 diamonds. */
  376.  
  377.   glTranslatef(0, 1.2, 0);
  378.   glColor3f(1.0, 1.0, 0.0);
  379.   diamond(btn_state[0]);
  380.  
  381.   glTranslatef(-1.2, -1.2, 0);
  382.   glColor3f(1.0, 1.0, 1.0);
  383.   diamond(btn_state[1]);
  384.  
  385.   glTranslatef(1.2, -1.2, 0);
  386.   glColor3f(0.0, 0.0, 1.0);
  387.   diamond(btn_state[2]);
  388.  
  389.   glTranslatef(1.2, 1.2, 0);
  390.   glColor3f(0.0, 1.0, 0.0);
  391.   diamond(btn_state[3]);
  392. }
  393.  
  394. void
  395. draw_scene(void)
  396. {
  397.   glClear(GL_COLOR_BUFFER_BIT);
  398.   glPushMatrix();
  399.   glTranslatef(tablet_pos[0], tablet_pos[1], 0);
  400.   glScalef(200, 200, 1);
  401.   puck();
  402.   glPopMatrix();
  403.   GLwDrawingAreaSwapBuffers(glxwidget);
  404.   if (!direct)
  405.     glFinish();         /* To improve net interactivity. */
  406. }
  407.  
  408. void
  409. resize(Widget w, XtPointer client_data, XtPointer call)
  410. {
  411.   GLwDrawingAreaCallbackStruct *call_data;
  412.   call_data = (GLwDrawingAreaCallbackStruct *) call;
  413.  
  414.   win_width = call_data->width;
  415.   win_height = call_data->height;
  416.   glViewport(0, 0, win_width, win_height);
  417. }
  418.